#include "printVisitor.h"

PrintVisitor::PrintVisitor(std::shared_ptr<Program> program)
{
    VisitProgram(program.get());
}

llvm::Value *PrintVisitor::VisitProgram(Program *p)
{
    for (auto &expr : p->nodeVec)
    {
        expr->Accept(this);
        llvm::outs() << "\n";
    }
    return nullptr;
}

llvm::Value *PrintVisitor::VisitDeclStmt(DeclStmt *decl)
{
    for (auto node : decl->nodeVec)
    {
        node->Accept(this);
    }
    return nullptr;
}

llvm::Value *PrintVisitor::VisitBlockStmt(BlockStmt *block)
{
    llvm::outs() << "{\n";
    for(const auto &node : block->nodeVec)
    {
        node->Accept(this);
        llvm::outs() << "\n";
    }
    llvm::outs() << "}\n";
    return nullptr;
}

llvm::Value *PrintVisitor::VisitIfStmt(IfStmt *ifStmt)
{
    llvm::outs() << "if (";
    ifStmt->condNode->Accept(this);
    llvm::outs() << ")\n";
    ifStmt->thenNode->Accept(this);
    llvm::outs() << "\n";
    if (ifStmt->elseNode)
    {
        llvm::outs() << "else\n";
        ifStmt->elseNode->Accept(this);
    }
    return nullptr;
}

llvm::Value *PrintVisitor::VisitVariableDecl(VariableDecl *decl)
{
    if (decl->type == CType::getIntTy())
    {
        llvm::outs() << "int " << llvm::StringRef(decl->token.ptr, decl->token.length) << ";";
    }
    return nullptr;
}

llvm::Value *PrintVisitor::VisitVariableAccessExpr(VariableAccessExpr *varaccExpr)
{
    llvm::outs() << llvm::StringRef(varaccExpr->token.ptr, varaccExpr->token.length);
    return nullptr;
}

llvm::Value *PrintVisitor::VisitAssignExpr(AssignExpr *assignExpr)
{
    assignExpr->left->Accept(this);

    llvm::outs() << " = ";

    assignExpr->right->Accept(this);
    return nullptr;
}

llvm::Value *PrintVisitor::VisitBinaryExpr(BinaryExpr *binaryExpr)
{
    // 后序遍历
    binaryExpr->left->Accept(this);

    switch (binaryExpr->op)
    {
    case OpCode::add:
    {
        llvm::outs() << " + ";
        break;
    }
    case OpCode::sub:
    {
        llvm::outs() << " - ";
        break;
    }
    case OpCode::mul:
    {
        llvm::outs() << " * ";
        break;
    }
    case OpCode::div:
    {
        llvm::outs() << " / ";
        break;
    }
    default:
    {
        break;
    }
    }

    binaryExpr->right->Accept(this);

    return nullptr;
}

llvm::Value *PrintVisitor::VisitNumberExpr(NumberExpr *factorExpr)
{
    llvm::outs() << llvm::StringRef(factorExpr->token.ptr, factorExpr->token.length);
    return nullptr;
}